/*******************************************************************************
 * Copyright (c) 2007 University of Oslo.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     University of Oslo - initial API and implementation
 *******************************************************************************/

package com.cea.papyrus.diagram.sequence.sedi.editor;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.gef.palette.ConnectionCreationToolEntry;
import org.eclipse.gef.palette.CreationToolEntry;
import org.eclipse.gef.palette.MarqueeToolEntry;
import org.eclipse.gef.palette.PaletteContainer;
import org.eclipse.gef.palette.PaletteDrawer;
import org.eclipse.gef.palette.PaletteEntry;
import org.eclipse.gef.palette.PaletteGroup;
import org.eclipse.gef.palette.PaletteRoot;
import org.eclipse.gef.palette.PaletteSeparator;
import org.eclipse.gef.palette.PaletteStack;
import org.eclipse.gef.palette.PanningSelectionToolEntry;
import org.eclipse.gef.palette.ToolEntry;
import org.eclipse.gef.requests.CreationFactory;
import org.eclipse.gef.tools.AbstractTool;
import org.eclipse.gef.tools.MarqueeSelectionTool;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.uml2.uml.Comment;
import org.eclipse.uml2.uml.Constraint;
import org.eclipse.uml2.uml.DurationObservation;
import org.eclipse.uml2.uml.MessageSort;
import org.eclipse.uml2.uml.TimeObservation;
import org.eclipse.uml2.uml.UMLPackage;

import com.cea.papyrus.core.PapyrusMessages;
import com.cea.papyrus.core.PapyrusPlugin;
import com.cea.papyrus.core.pseudoelement.GraphicalLink;
import com.cea.papyrus.core.utils.Debug;
import com.cea.papyrus.diagram.sequence.pseudoelement.DurationObservationLink;
import com.cea.papyrus.diagram.sequence.pseudoelement.TimeObservationLink;

/**
 * Creates the editor palette.
 * 
 * @author Andreas Limyr
 * @author frankd@ifi.uio.no
 */
public class SeDiPaletteFactory {

	/**
	 * Sequence Diagram Palette constructor
	 * @param images
	 * @return
	 */
    public static PaletteRoot createPaletteRoot(ImageLibrary images) {
        PaletteRoot root = new PaletteRoot();

        root.add(createStandardTools(root));
        root.add(createMessageDrawer(images));
        root.add(createShapesDrawer(images));

        return root;
    }

    /**
     * Create standard tools added to the Paletter
     * @param root
     * @return the palette container that offers standard tools
     */
    private static PaletteContainer createStandardTools(final PaletteRoot root) {
        PaletteGroup group = new PaletteGroup("Standard tools");

        ToolEntry selectionTool = new PanningSelectionToolEntry();
        group.add(selectionTool);

        ToolEntry marqueeTool = new MarqueeToolEntry();
        marqueeTool.setToolProperty(MarqueeSelectionTool.PROPERTY_MARQUEE_BEHAVIOR,
                MarqueeSelectionTool.BEHAVIOR_NODES_AND_CONNECTIONS
                        | MarqueeSelectionTool.BEHAVIOR_CONNECTIONS_TOUCHED);
        marqueeTool.setToolProperty(AbstractTool.PROPERTY_UNLOAD_WHEN_FINISHED, true);
        group.add(marqueeTool);

        group.add(new PaletteSeparator());

        root.setDefaultEntry(selectionTool);
        return group;
    }

    /**
     * Create the Palette tools for Edge creation (messages, commentlink...)
     * @param images
     * @return
     */
    private static PaletteEntry createMessageDrawer(final ImageLibrary images) {

        PaletteGroup drawer = new PaletteGroup("Messages");

        final List<ToolEntry> entries = new ArrayList<ToolEntry>();

        ImageDescriptor img;
        ToolEntry tool;

        img = images.getImage(ImageLibrary.SIGNAL_TOOL);
        // defaultTool = tool = new ConnectionCreationToolEntry2(
        tool =
                new ConnectionCreationToolEntry2(PapyrusMessages.AddAsynchSignalCommand_Label,
                		PapyrusMessages.AddAsynchSignalCommand_Description, new SeDiEditorLinkFactory(
                                UMLPackage.eINSTANCE.getMessage(),
                                MessageSort.ASYNCH_SIGNAL_LITERAL), img, img);
        entries.add(tool);

        img = images.getImage(ImageLibrary.SYNCH_CALL_TOOL);
        tool =
                new ConnectionCreationToolEntry2(PapyrusMessages.AddSynchCallCommand_Label,
                		PapyrusMessages.AddSynchCallCommand_Description, new SeDiEditorLinkFactory(
                                UMLPackage.eINSTANCE.getMessage(), MessageSort.SYNCH_CALL_LITERAL),
                        img, img);
        entries.add(tool);

        img = images.getImage(ImageLibrary.ASYNCH_CALL_TOOL);
        tool =
                new ConnectionCreationToolEntry2(PapyrusMessages.AddAsynchCallCommand_Label,
                		PapyrusMessages.AddAsynchCallCommand_Description,
                        new SeDiEditorLinkFactory(UMLPackage.eINSTANCE.getMessage(),
                                MessageSort.ASYNCH_CALL_LITERAL), img, img);
        entries.add(tool);

        img = images.getImage(ImageLibrary.REPLY_TOOL);
        tool =
                new ConnectionCreationToolEntry2("Reply", "Add a Reply message to the diagram",
                        new SeDiEditorLinkFactory(UMLPackage.eINSTANCE.getMessage(),
                                MessageSort.REPLY_LITERAL), img, img);
        entries.add(tool);

        img = images.getImage(ImageLibrary.CREATE_TOOL);
        tool =
                new ConnectionCreationToolEntry2("Create", "Add a Create message to the diagram",
                        new SeDiEditorLinkFactory(UMLPackage.eINSTANCE.getMessage(),
                                MessageSort.CREATE_MESSAGE_LITERAL), img, img);
        entries.add(tool);

        img = images.getImage(ImageLibrary.DESTROY_TOOL);
        tool =
                new ConnectionCreationToolEntry2("Destroy", "Add a Destroy message to the diagram",
                        new SeDiEditorLinkFactory(UMLPackage.eINSTANCE.getMessage(),
                                MessageSort.DELETE_MESSAGE_LITERAL), img, img);
        entries.add(tool);

        drawer.addAll(entries);
        
		///////////////////////////////////////////////////////////////////
		// Begin of tool for Comment and constraint links
		///////////////////////////////////////////////////////////////////
		
		// Add GraphicalLink
        drawer.add(PapyrusPlugin.creationToolFactory.getConnectionCreationToolEntry(
				PapyrusMessages.AddGraphicalLinkCommand_Label,
				PapyrusMessages.AddGraphicalLinkCommand_Description,
				GraphicalLink.class,
				null));	
        
     // Add GraphicalLink
        drawer.add(PapyrusPlugin.creationToolFactory.getConnectionCreationToolEntry(
				PapyrusMessages.AddDurationObservationLinkCommand_Label,
				PapyrusMessages.AddDurationObservationLinkCommand_Description,
				DurationObservationLink.class,
				null));	
        
     // Add GraphicalLink
        drawer.add(PapyrusPlugin.creationToolFactory.getConnectionCreationToolEntry(
        		PapyrusMessages.AddTimeObservationLinkCommand_Label,
        		PapyrusMessages.AddTimeObservationLinkCommand_Description,
				TimeObservationLink.class,
				null));	

        return drawer;
    }

    // The tool palette has been changed between Eclipse <= 3.0/RSM
    // and Eclipse >= 3.1.
    //
    // We want connection tools to be handled somewhat different from the
    // default configuration. Firstly, we want the tool to be automatically
    // deselected after it has been used once, just like the object tools.
    // Secondly, we want the newly created connection to be automatically
    // selected.
    // 
    // In 3.1 a call to
    // toolEntry.setToolProperty(
    // AbstractTool.PROPERTY_UNLOAD_WHEN_FINISHED, Boolean.TRUE);
    // is sufficient to achieve the first feature. The second feature
    // can similarly (in 3.1) be programmed by calling
    // toolEntry.setToolClass(SeDiConnectionCreationTool.class)
    //
    // Neither of these mechanims are available in earlier version of GEF
    // so we have to subclass and override methods.
    private static class ConnectionCreationToolEntry2 extends ConnectionCreationToolEntry {
        public ConnectionCreationToolEntry2(String label, String shortDesc,
                CreationFactory factory, ImageDescriptor iconSmall, ImageDescriptor iconLarge) {
            super(label, shortDesc, factory, iconSmall, iconLarge);
            // 3.1:
            setToolClass(SeDiConnectionCreationTool.class);
        }

        // 3.0:
        // public Tool createTool() {
        // return new SeDiConnectionCreationTool(this.factory);
        // }
    }
    
    /**
     * Create Palette container that contains tools for the creation of 
     * UML elements in the sequence diagram
     * @param images
     * @return the palette container with creation tools.
     */
    private static PaletteContainer createShapesDrawer(final ImageLibrary images) {
        PaletteDrawer componentsDrawer = new PaletteDrawer("Uml Element");
        List<PaletteEntry> entries = new ArrayList<PaletteEntry>();
        PaletteEntry entry;
        ImageDescriptor img;
        try {    		
            // Interaction
            PaletteStack paletteStack = new PaletteStack("", "", null);
            img = images.getImage(ImageLibrary.INTERACTION_TOOL);
            entry =
                    new CreationToolEntry(PapyrusMessages.AddInteractionCommand_Label,
                    		PapyrusMessages.AddInteractionCommand_Description,
                            new SeDiEditorToolFactory(UMLPackage.eINSTANCE.getInteraction()), img,
                            img);
            entries.add(entry);
            // Interaction Use
            img = images.getImage(ImageLibrary.INTERACTION_USE_TOOL);
            entry =
                    new CreationToolEntry(PapyrusMessages.AddInteractionUseCommand_Label,
                    		PapyrusMessages.AddInteractionUseCommand_Description, new SeDiEditorToolFactory(
                                    UMLPackage.eINSTANCE.getInteractionUse()), img, img);
            entries.add(entry);

            // Lifeline
            img = images.getImage(ImageLibrary.LIFELINE_TOOL);
            entry =
                    new CreationToolEntry(PapyrusMessages.AddLifelineCommand_Label,
                    		PapyrusMessages.AddLifelineCommand_Description,
                            new SeDiEditorToolFactory(UMLPackage.eINSTANCE.getLifeline()), img, img);
            entries.add(entry);

            // Execution Specification
            // Behavior
            img = images.getImage(ImageLibrary.BEHAVIOR_EXECUTION_SPECIFICATION_TOOL);
            entry =
                    new CreationToolEntry(PapyrusMessages.AddBehaviorExecutionSpecificationCommand_Label,
                    		PapyrusMessages.AddBehaviorExecutionSpecificationCommand_Description,
                            new SeDiEditorToolFactory(UMLPackage.eINSTANCE
                                    .getBehaviorExecutionSpecification()), img, img);
            entries.add(entry);
            // Action
            img = images.getImage(ImageLibrary.ACTION_EXECUTION_SPECIFICATION_TOOL);
            entry =
                    new CreationToolEntry(PapyrusMessages.AddActionExecutionSpecificationCommand_Label,
                    		PapyrusMessages.AddActionExecutionSpecificationCommand_Description,
                            new SeDiEditorToolFactory(UMLPackage.eINSTANCE
                                    .getActionExecutionSpecification()), img, img);
            entries.add(entry);

            // Destruction Event
            img = images.getImage(ImageLibrary.DESTRUCTION_EVENT_TOOL);
            entry =
                    new CreationToolEntry(PapyrusMessages.AddDestructionEventCommand_Label,
                    		PapyrusMessages.AddDestructionEventCommand_Description, new SeDiEditorToolFactory(
                                    UMLPackage.eINSTANCE.getDestructionEvent()), img, img);
            entries.add(entry);

            // state invariant
            img = images.getImage(ImageLibrary.STATE_INVARIANT_TOOL);
            entry =
                    new CreationToolEntry(PapyrusMessages.AddStateInvariantCommand_Label,
                    		PapyrusMessages.AddStateInvariantCommand_Description, new SeDiEditorToolFactory(
                                    UMLPackage.eINSTANCE.getStateInvariant()), img, img);
            entries.add(entry);

            // Fragment
            paletteStack = new PaletteStack("", "", null);
            // CombinedFragment
            img = images.getImage(ImageLibrary.COMBINED_FRAGMENT_TOOL);
            // defaultTool = entry = new CreationToolEntry(
            entry =
                    new CreationToolEntry(PapyrusMessages.AddCombinedFragmentCommand_Label,
                    		PapyrusMessages.AddCombinedFragmentCommand_Description,
                            new SeDiEditorToolFactory(UMLPackage.eINSTANCE.getCombinedFragment()),
                            img, img);
            paletteStack.add(entry);
            // Interaction Operand.
            img = images.getImage(ImageLibrary.SEPARATOR_TOOL);
            entry =
                    new ConnectionCreationToolEntry2(
                    		PapyrusMessages.AddInteractionOperandCommand_Label,
                    		PapyrusMessages.AddInteractionOperandCommand_Description,
                            new SeDiEditorLinkFactory(UMLPackage.eINSTANCE.getInteractionOperand()),
                            img, img);
            paletteStack.add(entry);
            // Guard
            img = images.getImage(ImageLibrary.INTERACTION_OPERAND_GUARD_TOOL);
            entry =
                    new CreationToolEntry(PapyrusMessages.AddGuardCommand_Label,
                    		PapyrusMessages.AddGuardCommand_Description,
                            new SeDiEditorToolFactory(UMLPackage.eINSTANCE
                                    .getInteractionConstraint()), img, img);
            paletteStack.add(entry);
            // Continuation
            img = images.getImage(ImageLibrary.CONTINUATION_TOOL);
            entry =
                    new CreationToolEntry(PapyrusMessages.AddContinuationCommand_Label,
                    		PapyrusMessages.AddContinuationCommand_Description,
                            new SeDiEditorToolFactory(UMLPackage.eINSTANCE.getContinuation()), img,
                            img);
            paletteStack.add(entry);
            entries.add(paletteStack);
            
            ///////////////////////////////////////////////////////////////////
    		// TimeObservation creation
    		///////////////////////////////////////////////////////////////////	
    		entries.add(PapyrusPlugin.creationToolFactory.getCombinedTemplateCreationToolEntry(
    				PapyrusMessages.AddTimeObservationCommand_Label,
    				PapyrusMessages.AddTimeObservationCommand_Description,
    				TimeObservation.class,
    				null));
    		///////////////////////////////////////////////////////////////////
    		// DurationObservation creation
    		///////////////////////////////////////////////////////////////////	
    		entries.add(PapyrusPlugin.creationToolFactory.getCombinedTemplateCreationToolEntry(
    				PapyrusMessages.AddDurationObservationCommand_Label,
    				PapyrusMessages.AddDurationObservationCommand_Description,
    				DurationObservation.class,
    				null));
            
    		///////////////////////////////////////////////////////////////////
    		// Comment creation
    		///////////////////////////////////////////////////////////////////	
    		entries.add(PapyrusPlugin.creationToolFactory.getCombinedTemplateCreationToolEntry(
    				PapyrusMessages.AddCommentCommand_Label,
    				PapyrusMessages.AddCommentCommand_Description,
    				Comment.class,
    				null));
    		
    		///////////////////////////////////////////////////////////////////
    		// Constraint creation
    		///////////////////////////////////////////////////////////////////	
    		entries.add(PapyrusPlugin.creationToolFactory.getCombinedTemplateCreationToolEntry(
    				PapyrusMessages.AddConstraintCommand_Label,
    				PapyrusMessages.AddConstraintCommand_Description,
    				Constraint.class,
    				null));
    		

        } catch (Exception e) {
            Debug.log(e);
        }
        componentsDrawer.addAll(entries);
        return componentsDrawer;
    }
}
